import { UserOnline } from '@/models/monitor/user-online.model';
import { getAddressByIp } from "@/utils/ip/ip.util";
import { UAParser } from 'ua-parser-js';
import { UserInfo } from '@/utils/security/jwt.util';
import { getLogger } from '@/utils/logger';
import cacheUtils from '@/utils/cache/cache.util';
import DateUtil from '@/utils/javaScript/date.util';

// 定义常量
// const ONLINE_USER_KEY_PREFIX = (process.env.REDIS_PREFIX || 'ruoyi:') + 'login_tokens';
export const ONLINE_USER_KEY_PREFIX = 'login_tokens';
// 创建常规日志记录器（不输出到控制台）
const logger = getLogger('user-online', {
  console: false
});
// 创建控制台日志记录器
const consoleLogger = getLogger('user-online');

/**
 * JWT <-> UUID 映射缓存操作
 */
const JWT_UUID_MAP_PREFIX = 'login_token_map';

/**
 * 在线用户服务
 */
class UserOnlineService {
  /**
   * 将登录用户信息转换为在线用户信息
   * @param tokenId 令牌ID
   * @param userInfo 用户信息
   * @param ipaddr IP地址
   * @param userAgent 用户代理字符串
   * @returns 在线用户信息
   */
  async loginUserToUserOnline(
    tokenId: string,
    userInfo: UserInfo,
    ipaddr: string,
    userAgent: string
  ): Promise<UserOnline> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`转换登录用户信息: userId=${userInfo.userId}, userName=${userInfo.userName}`);
      
      // 解析用户代理
      logger.debug(`解析用户代理: ${userAgent}`);
      const parser = new UAParser(userAgent);
      const browser = parser.getBrowser();
      const os = parser.getOS();
      
      // 解析IP地址获取地理位置
      logger.debug(`解析IP地址: ${ipaddr}`);
      const loginLocation = await getAddressByIp(ipaddr);
      
      // 组装在线用户对象
      const userOnline: UserOnline = {
        tokenId,
        userId: userInfo.userId,
        userName: userInfo.userName,
        ipaddr,
        loginLocation,
        browser: `${browser.name || ''} ${browser.version || ''}`.trim(),
        os: `${os.name || ''} ${os.version || ''}`.trim(),
        deptName: userInfo.deptName || '',
        loginTime: DateUtil.formatDate(DateUtil.YYYY_MM_DD_HH_MM_SS)
      };
      
      // 记录操作结果
      logger.info(`用户信息转换完成: userId=${userInfo.userId}, tokenId=${tokenId}`);
      
      return userOnline;
    } catch (error) {
      consoleLogger.error(`转换登录用户信息失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('转换登录用户信息失败');
    }
  }
  
  /**
   * 保存在线用户信息到Redis
   * @param tokenId 令牌ID（不包含前缀）
   * @param userOnline 在线用户信息
   * @param expire 过期时间（秒）
   */
  async saveOnlineUser(tokenId: string, userOnline: UserOnline, expire: number): Promise<void> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`保存在线用户信息: tokenId=${tokenId}, userId=${userOnline.userId}`);
      
      const cacheResult = await cacheUtils.set(`${ONLINE_USER_KEY_PREFIX}:${tokenId}`, userOnline, expire);
      
      if (!cacheResult.success) {
        const errorMsg = cacheResult.error?.message || String(cacheResult.error);
        consoleLogger.error(`保存在线用户信息失败: ${errorMsg}`);
        throw new Error(`保存在线用户信息失败: ${errorMsg}`);
      }
      
      // 记录操作结果
      logger.info(`在线用户信息保存成功: tokenId=${tokenId}, userId=${userOnline.userId}, 过期时间=${expire}秒`);
    } catch (error) {
      consoleLogger.error(`保存在线用户信息失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('保存在线用户信息失败');
    }
  }
  
  /**
   * 查询在线用户列表
   * @param ipaddr IP地址过滤条件
   * @param userName 用户名过滤条件
   * @returns 在线用户列表
   */
  async getOnlineUserList(ipaddr?: string, userName?: string): Promise<UserOnline[]> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`查询在线用户列表: ipaddr=${ipaddr || '无'}, userName=${userName || '无'}`);
      
      const pattern = `${ONLINE_USER_KEY_PREFIX}:*`;
      const keysResult = await cacheUtils.keys(pattern);
      const userOnlineList: UserOnline[] = [];
      
      if (keysResult.success && keysResult.data) {
        logger.debug(`获取到Redis键: 数量=${keysResult.data.length}`);
        
        for (const key of keysResult.data) {
          const tokenId = key.split(`${ONLINE_USER_KEY_PREFIX}:`)[1];
          const userOnlineResult = await cacheUtils.get<UserOnline>(`${ONLINE_USER_KEY_PREFIX}:${tokenId}`);
          
          if (userOnlineResult.success && userOnlineResult.data) {
            const userOnline = userOnlineResult.data;
            
            // 过滤条件
            if (ipaddr && userName) {
              if (
                userOnline.ipaddr.includes(ipaddr) &&
                userOnline.userName.includes(userName)
              ) {
                userOnlineList.push(userOnline);
              }
            } else if (ipaddr) {
              if (userOnline.ipaddr.includes(ipaddr)) {
                userOnlineList.push(userOnline);
              }
            } else if (userName) {
              if (userOnline.userName.includes(userName)) {
                userOnlineList.push(userOnline);
              }
            } else {
              userOnlineList.push(userOnline);
            }
          }
        }
      }
      
      // 按登录时间排序（降序）
      const result = userOnlineList.sort(
        (a, b) => new Date(b.loginTime).getTime() - new Date(a.loginTime).getTime()
      );
      
      // 记录查询结果
      logger.info(`在线用户列表查询完成: 总数=${result.length}`);
      
      return result;
    } catch (error) {
      consoleLogger.error(`查询在线用户列表失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('查询在线用户列表失败');
    }
  }
  
  /**
   * 强制退出用户
   * @param tokenId 令牌ID（不包含前缀）
   * @returns 是否成功
   */
  async forceLogout(tokenId: string): Promise<boolean> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`强制退出用户: tokenId=${tokenId}`);
      
      const cacheResult = await cacheUtils.del(`${ONLINE_USER_KEY_PREFIX}:${tokenId}`);
      
      if (!cacheResult.success) {
        const errorMsg = cacheResult.error?.message || String(cacheResult.error);
        consoleLogger.error(`强制退出用户失败: tokenId=${tokenId}, 错误=${errorMsg}`);
        return false;
      }
      
      // 记录操作结果
      logger.info(`强制退出用户成功: tokenId=${tokenId}`);
      
      return true;
    } catch (error) {
      consoleLogger.error(`强制退出用户失败: ${error instanceof Error ? error.message : String(error)}`);
      return false;
    }
  }
  
  /**
   * 根据用户ID强制退出用户
   * @param userId 用户ID
   * @returns 被强制退出的会话数
   */
  async forceLogoutByUserId(userId: number): Promise<number> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`根据用户ID强制退出用户: userId=${userId}`);
      
      const pattern = `${ONLINE_USER_KEY_PREFIX}:*`;
      const keysResult = await cacheUtils.keys(pattern);
      let count = 0;
      
      if (keysResult.success && keysResult.data) {
        logger.debug(`获取到Redis键: 数量=${keysResult.data.length}`);
        
        for (const key of keysResult.data) {
          const tokenId = key.replace(`${ONLINE_USER_KEY_PREFIX}:`, '');
          const userOnlineResult = await cacheUtils.get<UserOnline>(`${ONLINE_USER_KEY_PREFIX}:${tokenId}`);
          
          if (userOnlineResult.success && userOnlineResult.data && userOnlineResult.data.userId === userId) {
            logger.debug(`找到匹配的用户会话: tokenId=${tokenId}, userId=${userId}`);
            const delResult = await cacheUtils.del(`${ONLINE_USER_KEY_PREFIX}:${tokenId}`);
            
            if (delResult.success) {
              count++;
            }
          }
        }
      }
      
      // 记录操作结果
      logger.info(`根据用户ID强制退出完成: userId=${userId}, 退出会话数=${count}`);
      
      return count;
    } catch (error) {
      consoleLogger.error(`根据用户ID强制退出用户失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('根据用户ID强制退出用户失败');
    }
  }

  /**
   * 根据uuid获取在线用户信息
   * @param uuid uuid字符串
   * @returns UserOnline对象或null
   */
  async getOnlineUserByUuid(uuid: string): Promise<UserOnline | null> {
    try {
      // 使用consoleLogger记录操作开始
      consoleLogger.info(`根据UUID获取在线用户信息: uuid=${uuid}`);
      
      const cacheResult = await cacheUtils.get<UserOnline>(`${ONLINE_USER_KEY_PREFIX}:${uuid}`);
      
      if (cacheResult.success && cacheResult.data) {
        // 记录查询结果
        logger.info(`在线用户信息获取成功: uuid=${uuid}, userId=${cacheResult.data.userId}`);
        return cacheResult.data;
      }
      
      logger.info(`未找到在线用户信息: uuid=${uuid}`);
      return null;
    } catch (error) {
      consoleLogger.error(`根据UUID获取在线用户信息失败: ${error instanceof Error ? error.message : String(error)}`);
      throw new Error('根据UUID获取在线用户信息失败');
    }
  }
}

export default new UserOnlineService();

/**
 * 设置jwt与uuid的映射关系
 * @param jwt jwt字符串
 * @param uuid uuid字符串
 * @param ttl 过期时间（秒）
 */
export async function setJwtUuidMapping(jwt: string, uuid: string, ttl: number): Promise<void> {
  try {
    // 使用consoleLogger记录操作开始
    consoleLogger.info(`设置JWT-UUID映射: uuid=${uuid}, ttl=${ttl}秒`);
    
    const cacheResult = await cacheUtils.set(`${JWT_UUID_MAP_PREFIX}:${jwt}`, uuid, ttl);
    
    if (!cacheResult.success) {
      const errorMsg = cacheResult.error?.message || String(cacheResult.error);
      consoleLogger.error(`设置JWT-UUID映射失败: uuid=${uuid}, 错误=${errorMsg}`);
      throw new Error(`设置JWT-UUID映射失败: ${errorMsg}`);
    } else {
      logger.info(`JWT-UUID映射设置成功: uuid=${uuid}, ttl=${ttl}秒`);
    }
  } catch (error) {
    consoleLogger.error(`设置JWT-UUID映射失败: ${error instanceof Error ? error.message : String(error)}`);
    throw new Error('设置JWT-UUID映射失败');
  }
}

/**
 * 通过jwt获取uuid
 * @param jwt jwt字符串
 * @returns uuid字符串或null
 */
export async function getUuidByJwt(jwt: string): Promise<string | null> {
  try {
    // 使用consoleLogger记录操作开始
    consoleLogger.info(`通过JWT获取UUID`);
    
    const cacheResult = await cacheUtils.get<string>(`${JWT_UUID_MAP_PREFIX}:${jwt}`);
    
    if (cacheResult.success && cacheResult.data) {
      logger.info(`通过JWT获取UUID成功: uuid=${cacheResult.data}`);
      return cacheResult.data;
    }
    
    logger.info(`未找到JWT对应的UUID`);
    return null;
  } catch (error) {
    consoleLogger.error(`通过JWT获取UUID失败: ${error instanceof Error ? error.message : String(error)}`);
    throw new Error('通过JWT获取UUID失败');
  }
}

/**
 * 删除jwt与uuid的映射关系
 * @param jwt jwt字符串
 */
export async function deleteJwtUuidMapping(jwt: string): Promise<void> {
  try {
    // 使用consoleLogger记录操作开始
    consoleLogger.info(`删除JWT-UUID映射`);
    
    const cacheResult = await cacheUtils.del(`${JWT_UUID_MAP_PREFIX}:${jwt}`);
    
    if (!cacheResult.success) {
      const errorMsg = cacheResult.error?.message || String(cacheResult.error);
      consoleLogger.error(`删除JWT-UUID映射失败: 错误=${errorMsg}`);
      throw new Error('删除JWT-UUID映射失败');
    } else {
      logger.info(`JWT-UUID映射删除成功`);
    }
  } catch (error) {
    consoleLogger.error(`删除JWT-UUID映射失败: ${error instanceof Error ? error.message : String(error)}`);
    throw new Error('删除JWT-UUID映射失败');
  }
}